const path = require('path');
const webpack = require('webpack');
const webpackMerge = require('webpack-merge');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const HtmlWebPackPlugin = require('html-webpack-plugin');
const WebpackCopyPlugin = require('copy-webpack-plugin');
const ModulePlugin = require('./config/webpack.plugin');
const proxy = require('./config/server.proxy');

const dll = require('./config/dll.json');
const { name, version, config } = require('./package.json');

const optimization = {
  minimize: true,
  minimizer: [
    new UglifyJsPlugin({
      cache: true,
      parallel: true,
      uglifyOptions: {
        output: {
          comments: false
        },
        compress: {
          warnings: false,
          collapse_vars: true,
          reduce_vars: true,
          drop_console: true
        }
      }
    })
  ],
  namedChunks: true,
  splitChunks: {
    cacheGroups: {
      vendors: false
    }
  }
};

const getModule = (isEnvProduction, app) => {
  const styleLoader = 'style-loader';







  return {
    rules: [
      {
        test: /\.(js|jsx)$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: [['@babel/preset-env', { modules: 'cjs' }], '@babel/preset-react'],
            plugins: [
              ['@babel/plugin-proposal-decorators', { legacy: true }],
              ['@babel/plugin-proposal-class-properties', { loose: true }],
              ['@babel/plugin-transform-runtime', { regenerator: true }]
            ],
            cacheDirectory: true
          }
        }
      },
      {
        test: /\.less$/,
        include: /\.module\.less$/,
        exclude: /node_modules/,
        use: [
          styleLoader,
          {
            loader: 'css-loader',
            options: {
              importLoaders: 1,
              modules: {
                localIdentName: '[local]_[hash:base64:5]'
              },
              localsConvention: 'camelCase'
            }
          },
          'less-loader'
        ],
        sideEffects: true
      },
      {
        test: /\.less$/,
        exclude: /\.module\.less$/,
        use: [
          styleLoader,
          'css-loader',
          'less-loader'
        ]
      },
      {
        test: /\.css$/i,
        use: [
          styleLoader,
          'css-loader'
        ]
      },
      {
        test: /\.(png|jpg|jpeg|gif)$/,
        use: [
          {
            loader: 'url-loader',
            options: {
              limit: 1024 * 32,
              name: 'images/[name].[hash:8].[ext]'
            }
          }
        ]
      },
      {
        test: /\.(woff(2)?|otf|eot|svg|ttf)$/,
        use: [
          {
            loader: 'url-loader',
            options: {
              limit: 1024 * 16,
              name: 'fonts/[name].[ext]'
            }
          }
        ]
      }
    ]
  };
};

module.exports = (props, env) => {
  const mode = env.mode;
  const isEnvProduction = mode === 'production';
  const buildPath = path.resolve(process.cwd(), config.build[env.build || mode], config.publicPath);
  const appPath = path.resolve(process.cwd());

  console.log('mode', mode);
  console.log('appPath', appPath);

  const appConfig = (appName) => {
    console.log('appName', appName);
    const resolve = {
      extensions: ['.jsx', '.js', '.json', '.css', '.less'],
      alias: {
        '@shell-ui': path.join(appPath, 'src'),
        '@variables': path.join(appPath, 'assets/styles/variables.less')
      }
    };

    const originalMockPath = path.resolve(process.cwd(), '../mock-api/dist/mock');
    const deployMockPath = path.resolve(process.cwd(), 'deploy/dist/mock/');

    const pluginsCommon = [
      new webpack.ProvidePlugin({
        _: 'lodash'
      }),
      new webpack.DefinePlugin({
        'process.env': {
          NODE_ENV: JSON.stringify(mode),
          APP_NAME: JSON.stringify(appName),
          SUB_MODULE_OUTPUT: JSON.stringify(config.output)
        }
      }),
      new webpack.ContextReplacementPlugin(/moment[/\\]locale$/, /en/),
      new webpack.DllReferencePlugin({
        context: path.resolve(process.cwd()),
        manifest: path.join(buildPath, 'dll.manifest.json')
      })
    ];

    const commonConfig = {
      name: appName,
      mode,
      devtool: isEnvProduction ? false : 'cheap-module-eval-source-map',
      entry: {
        [appName]: `./${config.entry[mode]}`
      },
      output: {
        path: buildPath,
        publicPath: isEnvProduction ? `./${config.publicPath}/` : '/',
        filename: '[name].js',
        // chunkFilename
        library: 'common'
      },
      module: getModule(isEnvProduction, 'shell'),
      resolve,
      externals: {
        '@common/components': 'window.common.components',
        '@common/utils': 'window.common.utils',
        '@common/hooks': 'window.common.hooks',
        '@common/shell': 'window.common.shell'
      }
    };

    const developmentConfig = {
      stats: 'minimal',
      watchOptions: {
        aggregateTimeout: 200,
        poll: 100,
        ignored: /node_modules/
      },
      devServer: {
        host: '0.0.0.0',
        contentBase: './dist',
        port: config.port,
        compress: true,
        hot: true,
        inline: true,
        proxy
      },
      plugins: [
        ...pluginsCommon,
        new webpack.HotModuleReplacementPlugin(),
        new HtmlWebPackPlugin({
          template: './config/index.html',
          filename: 'index.html'
        })
      ]
    };

    const productionConfig = {
      optimization,
      plugins: [
        ...pluginsCommon,
        new CleanWebpackPlugin(deployMockPath, { allowExternal: true }),
        new MiniCssExtractPlugin({
          filename: 'css/[name].css',
          chunkFilename: 'css/[name].[chunkhash:6].chunk.css'
        }),
        new ModulePlugin({ name: appName, version }),
        new HtmlWebPackPlugin({
          template: './config/index.html',
          filename: '../index.html',
          hash: true,
          minify: {
            removeComments: true,
            collapseWhitespace: true,
            removeRedundantAttributes: true,
            useShortDoctype: true,
            removeEmptyAttributes: true,
            removeStyleLinkTypeAttributes: true,
            keepClosingSlash: true,
            minifyJS: true,
            minifyCSS: true,
            minifyURLs: true
          }
        }),
        new WebpackCopyPlugin([
          {
            from: originalMockPath,
            to: deployMockPath
          }
        ])
      ]
    };

    switch (mode) {
      case 'development':
        return webpackMerge(commonConfig, developmentConfig);
      case 'production':
      default:
        return webpackMerge(commonConfig, productionConfig);
    }
  };

  return [
    {
      name: 'dll',
      entry: {
        dll
      },
      output: {
        path: buildPath,
        publicPath: `./${config.publicPath}/`,
        filename: '[name].js',
        library: '[name]'
      },
      module: getModule(isEnvProduction),
      optimization,
      plugins: [
        new CleanWebpackPlugin(buildPath, { allowExternal: true }),
        new webpack.DllPlugin({
          name: '[name]',
          context: path.resolve(process.cwd()),
          path: path.join(buildPath, 'dll.manifest.json')
        }),
        new ModulePlugin({ name: 'dll', version })
      ]
    },
    appConfig(name)
  ];
};
